﻿using System.Collections.Generic;

namespace dPet.Application.Services.Implementation
{
	using AutoMapper;
	using dPet.Application.DataObjects;
	using dPet.Domain.Models;
	using dPet.Domain.Repositories;
	using dPet.Domain.Services;
	using dPet.Domain.Specifications;
	using dPet.Infrastructure.Logging;
	using Hangerd;
	using Hangerd.Repository;

	public class AccountService : ServiceBase, IAccountService
	{
		#region Repository

		private readonly IHospitalRepository _hospitalRepository;
		private readonly IStaffRepository _staffRepository;
		private readonly IStaffRoleRepository _staffRoleRepository;

		#endregion

		#region Services

		private readonly IAccountDomainService _accountDomainService;

		#endregion

		#region Constructors

		public AccountService(
			IRepositoryContext unitOfWork,
			IHospitalRepository hospitalRepository,
			IStaffRepository staffRepository,
			IStaffRoleRepository staffRoleRepository,
			IAccountDomainService accountDomainService)
			: base(unitOfWork)
		{
			_hospitalRepository = hospitalRepository;
			_staffRepository = staffRepository;
			_staffRoleRepository = staffRoleRepository;
			_accountDomainService = accountDomainService;
		}

		#endregion

		public MessagedResult<bool> AddStaff(StaffDto staffDto, IOperator @operator)
		{
			return TryLoggedOperate(@operator, "用户管理", "添加员工", (ref Staff newStaff) =>
			{
				var hospital = _hospitalRepository.Get(staffDto.HospitalId, false);

				if (hospital == null)
				{
					throw new HangerdException("医院信息不存在");
				}

				var staffRole = _staffRoleRepository.Get(staffDto.StaffRole.Id, true);

				if (staffRole == null)
				{
					throw new HangerdException("角色信息不存在");
				}

				newStaff = _accountDomainService.RegisterNewStaff(
					hospital, staffRole, staffDto.LoginName, staffDto.Password, staffDto.Name, staffDto.Contact);

				_staffRepository.Add(newStaff, true);

				UnitOfWork.Commit();

				return true;
			});
		}

		public MessagedResult<bool> UpdateStaff(string staffId, StaffDto staffDto, IOperator @operator)
		{
			return TryLoggedOperate(@operator, "用户管理", "修改员工信息", (ref Staff staff) =>
			{
				staff = _staffRepository.Get(staffId, true, s => s.StaffRole);

				if (staff == null)
				{
					throw new HangerdException("员工信息不存在");
				}

				if (staffDto.StaffRole != null && !string.IsNullOrWhiteSpace(staffDto.StaffRole.Id))
				{
					var staffRole = _staffRoleRepository.Get(staffDto.StaffRole.Id, true);

					if (staffRole == null)
					{
						throw new HangerdException("角色信息不存在");
					}

					staff.StaffRole = staffRole;
				}

				staff.Name = staffDto.Name;
				staff.Contact = staffDto.Contact;

				_staffRepository.Update(staff, true);

				UnitOfWork.Commit();

				return true;
			});
		}

		public IEnumerable<StaffDto> GetStaffs(string hospitalId)
		{
			var spec = StaffSpecifications.HospitalIdEquals(hospitalId);
			var staffs = _staffRepository.GetAll(spec, false, s => s.StaffRole);

			return Mapper.Map<IEnumerable<Staff>, IEnumerable<StaffDto>>(staffs);
		}

		public StaffDto GetStaff(string id)
		{
			var staff = _staffRepository.Get(id, false, s => s.StaffRole);

			return Mapper.Map<Staff, StaffDto>(staff);
		}

		public StaffDto GetStaff(string loginName, string password)
		{
			var staff = _staffRepository.Get(StaffSpecifications.LoginNameEquals(loginName), false);

			if (staff != null && staff.ValidatePassword(password))
			{
				return Mapper.Map<Staff, StaffDto>(staff);
			}

			return null;
		}

		public MessagedResult<bool> ResetStaffPassword(string staffId, string newPassword, IOperator @operator)
		{
			return TryLoggedOperate(@operator, "用户管理", "重置登录密码", (ref Staff staff) =>
			{
				staff = _staffRepository.Get(staffId, true);

				if (staff == null)
				{
					throw new HangerdException("员工信息不存在");
				}

				staff.ChangePassword(newPassword);

				_staffRepository.Update(staff, false);

				UnitOfWork.Commit();

				return true;
			});
		}

		public MessagedResult<bool> ChangeStaffPassword(string staffId, string oldPassword, string newPassword, IOperator @operator)
		{
			return TryLoggedOperate(@operator, "用户管理", "修改登录密码", (ref Staff staff) =>
			{
				staff = _staffRepository.Get(staffId, true);

				if (staff == null)
				{
					throw new HangerdException("员工信息不存在");
				}

				if (!staff.ValidatePassword(oldPassword))
				{
					throw new HangerdException("原密码错误");
				}

				staff.ChangePassword(newPassword);

				_staffRepository.Update(staff, false);

				UnitOfWork.Commit();

				return true;
			});
		}
	}
}
